#pragma once

#include "Util.hpp"
#include "TcpServer.hpp"
#include "Socket.hpp"
#include <memory>
#include <unordered_map>

const std::string g_space = " ";
const std::string g_line_break = "\r\n";
const std::string g_line_sep = ": ";

const std::string web_root = "./wwwroot";
const std::string home_page = "index.html";
const std::string page_404 = "/404.html";


class HttpRequest
{
public:
    HttpRequest()
        :_is_interact(false)
    {}

    std::string Serialize()
    {
        return "";
    }

    void ParseReqLine(std::string& reqline)
    {
        std::stringstream ss(reqline);
        ss >> _method >> _url >> _version;
    }
    
    bool Deserialize(std::string& reqstr)
    {
        std::string reqline;
        bool res = Util::ReadOneLine(reqstr, &reqline, g_line_sep);
        LOG(LogLevel::DEBUG) << reqline;

        ParseReqLine(reqline);

        LOG(LogLevel::DEBUG) << "_method: " << _method;
        LOG(LogLevel::DEBUG) << "_url: " << _url;
        LOG(LogLevel::DEBUG) << "_version: " << _version;
        if(_url == "/")
            _url = web_root + _url + home_page;
        else
            _url = web_root + _url;

        const std::string temp = "?";
        auto pos = _url.find(temp);
        if(pos == std::string::npos) return true;
        _args = _url.substr(pos + temp.size());
        _url = _url.substr(0, pos);
        _is_interact = true;

        return true;
    }

        std::string Url() { return _url;}

    ~HttpRequest()
    {}

private:
    std::string _method;
    std::string _url;
    std::string _version;
    std::unordered_map<std::string, std::string> _headers;
    std::string _blank_line;
    std::string _text;
    
    std::string _args;
    bool _is_interact;
};

class HttpResponse
{
public:
    HttpResponse()
        :_version("HTTP/1.1")
        ,_code(200)
        ,_blank_line(g_line_break)
    {}

    void SetCode(int code)
    {
        _code = code;
        switch (_code)
        {
        case 200:
            _desc = "OK";
            break;
        case 404:
            _desc = "Not Found";
            break;
        case 301:
            _desc = "Moved Permanently";
            break;
        case 302:
            _desc = "See Other";
            break;
        default:
            break;
        }
    }

    void SetHeader(const std::string& key, const std::string& value)
    {
        auto it = _headers.find(key);
        if(it != _headers.end()) return ;
        _headers.insert(std::make_pair(key, value));
    }

    std::string Uri2Suffix(const std::string& targetfile)
    {
        auto pos = targetfile.rfind(".");
        if(pos == std::string::npos)
        {
            return "text/html";
        }
        std::string suffix = targetfile.substr(pos);
        if (suffix == ".html" || suffix == ".htm")
            return "text/html";
        else if (suffix == ".jpg")
            return "image/jpeg";
        else if (suffix == "png")
            return "image/png";
        else
            return "";
    }

    //服务器需要对发出去的请求序列化
    //结构化数据变成http格式的请求
    std::string Serialize()
    {
        // LOG(LogLevel::DEBUG) << "_version: " <<_version;
        // LOG(LogLevel::DEBUG) << "_code: " << _code;
        // LOG(LogLevel::DEBUG) << "_desc: " << _desc;

        std::string status_line = _version + g_space + std::to_string(_code) + g_space + _desc + g_line_break;
        std::string resp_header;
        for(auto& header : _headers)
        {
            std::string line = header.first + g_line_sep + header.second + g_line_break;
            resp_header += line;
        }

        

        return status_line + resp_header + _blank_line + _text;
    }

    void SetTargetFile(const std::string& target)
    {
        _target_file = target;
    }

    //服务器获取需要发送给客户端的数据
    bool MakeResponse()
    {
        if (_target_file == "./wwwroot/redir_test")
        {
            SetCode(301);
            SetHeader("Location", "https://www.qq.com/");
            return true;
        }

        int filesize = 0;
        bool res = Util::ReadFileContent(_target_file, &_text);
        if(!res)
        {
            _text = "";
            LOG(LogLevel::WARNING) << "client want get : " << _target_file << " but not found";
            SetCode(404);
            _target_file = web_root + page_404;
            filesize = Util::FileSize(_target_file);
            Util::ReadFileContent(_target_file, &_text);
            std::string suffix = Uri2Suffix(_target_file);
            SetHeader("Content-Type", suffix);
            SetHeader("Content-Length", std::to_string(filesize));
        }
        else
        {
            SetCode(200);
            filesize = Util::FileSize(_target_file);
            std::string suffix = Uri2Suffix(_target_file);
            SetHeader("Conent-Type", suffix);
            SetHeader("Conent-Length", std::to_string(filesize));
            
        }
        //LOG(LogLevel::DEBUG) << "_text: " << _text;
        return true;
    }

    void SetText(const std::string& t)
    {
        _text = t;
    }

    //客户端需要完成的任务
    bool Deserialize(std::string& reqstr)
    {
        return true;
    }

    ~HttpResponse()
    {}
public:
    std::string _version;
    int _code;
    std::string _desc;

    std::unordered_map<std::string, std::string> _headers;
    std::string _blank_line;
    std::string _text; 

    std::string _target_file;
};

class Http
{
public:
    Http(uint16_t port)
        :tsvrp(std::make_unique<TcpServer>(port))
    {}

    void HandlerHttpRequest(std::shared_ptr<Socket>& sock, InetAddr& client)
    {

        std::string http_reqstr;
        int n = sock->Recv(&http_reqstr);
        //这个存在一个问题，服务器收到的数据不一定是完整的，需要对报文的完整性进行判断
        //这里认为收到一个完整的数据
        if(n > 0)
        {
            HttpRequest req;
            req.Deserialize(http_reqstr);

            HttpResponse res;
            res.SetTargetFile(req.Url());
            res.MakeResponse();
            std::string res_str = res.Serialize();
            sock->Send(res_str);
        }

// #ifndef DEBUG
// #define DEBUG
// #ifndef DEBUG
//         std::string http_reqstr;
//         sock->Recv(&http_reqstr);
//         std::cout << http_reqstr;
// #endif
    }

    void Start()
    {
        tsvrp->Start([this](std::shared_ptr<Socket>& sock, InetAddr& client){
            this->HandlerHttpRequest(sock, client);
        });
    }

    ~Http()
    {}
private:
    std::unique_ptr<TcpServer> tsvrp;
};

